package org.wenhua.yuan.socket_server

import android.util.Log
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.net.ServerSocket
import java.net.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

/** SocketServer 服务端
 * 【测试提醒】使用注意事项：
 * 1，使用两台安卓真机
 * 2，须在同一wifi网络之下
 * 3，如果在同一个网络之下还是无法建立连接（如有报错如：System.err: java.net.NoRouteToHostException: Host unreachable）
 *    这种情况下，可以把两台手机都断开连接、断网，后重新连接同一WiFi。然后再进行客户端、服务端的连接。
 * 4，继续优化实现，参考使用  https://blog.csdn.net/ding3106/article/details/80714410
 * */
object SocketServer {

    private val TAG = SocketServer::class.java.simpleName

    private const val SOCKET_PORT = 10000

    private var socket: Socket? = null
    private var serverSocket: ServerSocket? = null

    private lateinit var serverCallback: ServerCallback

    private lateinit var outputStream: OutputStream

    var result = true

    // 服务端线程池
    private var serverThreadPool: ExecutorService? = null

    /** 开启服务 */
    fun startServer(callback: ServerCallback): Boolean {
        serverCallback = callback
        Thread {
            try {
                serverSocket = ServerSocket(SOCKET_PORT)
                while (true) {
                    Log.d("服务端进入while监听: ", "<<<执行accept()方法，且阻塞、监听>>>")
                    // 调用serverSocket的accept()方法，接收客户端发送的请求
                    socket = serverSocket?.accept()
                    Log.e("服务端进入while监听:", "服务器与客户端建立连接！！！")
                    serverCallback.onServerWarmingTip("server温馨提示：服务器与客户端建立连接！！！")
                    ServerThread(socket!!, serverCallback).start()
                }
            } catch (e: IOException) {
                Log.e("serverSocket-socket-IOException", e.toString())
                e.printStackTrace()
                result = false
            }
        }.start()
        return result
    }

    /** 关闭服务 */
    fun stopServer() {
        socket?.apply {
            shutdownInput()
            shutdownOutput()
            close()
        }
        serverSocket?.close()

        //关闭线程池
        serverThreadPool?.shutdownNow()
        serverThreadPool = null
    }

    /** 发送到客户端 */
    fun sendToClient(msg: String) {
        if (serverThreadPool == null) {
            serverThreadPool = Executors.newCachedThreadPool()
        }
        serverThreadPool?.execute {
            if (socket == null) {
                serverCallback.onServerWarmingTip("server温馨提示：客户端还未连接")
                return@execute
            }
            if (socket!!.isClosed) {
                serverCallback.onServerWarmingTip("server温馨提示：Socket已关闭")
                return@execute
            }
            outputStream = socket!!.getOutputStream()
            try {

                outputStream.write(msg.toByteArray())
                outputStream.flush()
            } catch (e: IOException) {
                e.printStackTrace()
                serverCallback.onServerWarmingTip("server温馨提示：向客户端发送${msg}失败")
            }
        }
    }

    /**
     * 回复心跳消息
     */
    fun replyHeartbeat() {
        if (serverThreadPool == null) {
            serverThreadPool = Executors.newCachedThreadPool()
        }
        val heartMessage = "[回复心跳消息：服务端，已收到！！！]"
        serverThreadPool?.execute {
            if (socket == null) {
                serverCallback.onServerWarmingTip("server温馨提示：客户端还未连接")
                return@execute
            }
            if (socket!!.isClosed) {
                serverCallback.onServerWarmingTip("server温馨提示：Socket已关闭")
                return@execute
            }
            outputStream = socket!!.getOutputStream()
            try {
                outputStream.write(heartMessage.toByteArray())
                outputStream.flush()
            } catch (e: IOException) {
                e.printStackTrace()
                serverCallback.onServerWarmingTip("server温馨提示：向客户端发送${heartMessage}失败")
            }
        }
    }

    class ServerThread(private val socket: Socket, private val serverCallback: ServerCallback) :
        Thread() {

        override fun run() {
            val inputStream: InputStream?
            try {
                inputStream = socket.getInputStream()
                val buffer = ByteArray(1024)
                var len: Int
                var receiveStr = ""
                if (inputStream.available() == 0) {
                    Log.e(TAG, "inputStream.available() == 0 收到的消息无效")
                }
                while (inputStream.read(buffer).also { len = it } != -1) {
                    receiveStr += String(buffer, 0, len, Charsets.UTF_8)
                    if (len < 1024) {
                        socket.inetAddress.hostAddress?.let {
                            if (receiveStr == "=== 客户端已向服务端建立连接，服务端发送心跳，收到请回复 ===") {//收到客户端发送的心跳消息
                                serverCallback.onHeartbeatClientMessage("server-heart-beat-get")
                                //准备回复
                                replyHeartbeat()
                            } else {
                                serverCallback.onReceiveClientMessage(it, receiveStr)
                            }
                        }
                        receiveStr = ""
                    }
                }
            } catch (e: IOException) {
                e.printStackTrace()
                when (e) {
                    is SocketTimeoutException -> {
                        Log.e(TAG, "连接超时，正在重连")
                    }
                    is NoRouteToHostException -> {
                        Log.e(TAG, "该地址不存在，请检查")
                    }
                    is ConnectException -> {
                        Log.e(TAG, "连接异常或被拒绝，请检查")
                    }
                    is SocketException -> {
                        when (e.message) {
                            "Already connected" -> Log.e(TAG, "连接异常或被拒绝，请检查")
                            "Socket closed" -> Log.e(TAG, "连接已关闭")
                        }
                    }
                }
            }
        }
    }

}
